package com.hua.customviews.widget

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Rect
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.MotionEvent
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import com.hua.customviews.databinding.LayoutSliderSelectorBinding
import java.math.RoundingMode
import java.text.DecimalFormat
import kotlin.math.abs

/**
 * 滑动条数值选择器
 * @author Hua
 * date: 2023年5月4日
 */
@Suppress("unused")
class SliderSelectorView(mContext: Context, attrs: AttributeSet?, defStyleAttr: Int) :
    ConstraintLayout(mContext, attrs, defStyleAttr) {
    private val mBinding = LayoutSliderSelectorBinding.inflate(LayoutInflater.from(mContext), this, true)

    init {
        initView()
    }

    constructor(mContext: Context, attrs: AttributeSet?) : this(mContext, attrs, 0) {
        initView()
    }

    constructor(mContext: Context) : this(mContext, null, 0) {
        initView()
    }

    //设置视图（外部操作）
    private var resetViewListener: ((binding: LayoutSliderSelectorBinding) -> Unit)? = null

    //滑动监听
    private var onSlidingListener: ((binding: LayoutSliderSelectorBinding, value: Float, position: Float, event: MotionEvent) -> Unit)? =
        null

    //可滑动长度
    private var sliderLength = 0

    //滑动起点
    private var sliderBarLeft = 0

    //滑动终点
    private var sliderBarRight = 0

    /**
     * 保留小数位数
     */
    var decimalLimit = 0

    /**
     *  颗粒感程度 0..1
     *  设置后滑动具有颗粒感（”嗒嗒嗒……“）
     */
    var grainyValue = 0f

    /**
     * 最小值
     */
    var minValue: Float = 0f
        set(value) {
            field = value
            mBinding.tvMinValue.text = value.toString()
        }

    /**
     * 最大值
     */
    var maxValue: Float = 100f
        set(value) {
            field = value
            mBinding.tvMaxValue.text = value.toString()
        }

    /**
     * 当前值
     */
    var value: Float = 0f
        set(value) {
            if (value < minValue) {
                //小于最小值取最小值
                field = minValue
            }
            if (value > maxValue) {
                //大于最小值取最大值
                field = maxValue
            }
            if (value in minValue..maxValue) {
                field = value
            }
            val pos = (field - minValue) / (maxValue - minValue)
            if (position != pos) position = pos
            mBinding.tvShowValue.text = getValueString(field)
        }

    /**
     * 获取格式化后的值
     */
    val formattedValue: Float
        get() = getValueString(value).toFloat()

    /**
     * 当前位置（百分比）
     */
    var position = 0.5f
        set(pos) {
            field = pos
            mBinding.apply {
                //仅改变滑动按钮的HorizontalBias即可实现整体滑动效果，与之关联的View会根据约束集自动调整位置
                ConstraintSet().apply {
                    clone(root)
                    setHorizontalBias(ivSliderBtn.id, pos)
                    applyTo(root)
                }
            }
        }

    /**
     * 最大值显示文字
     */
    val tvMaxValue get() = mBinding.tvMaxValue

    /**
     * 最小值显示文字
     */
    val tvMinValue get() = mBinding.tvMinValue

    /**
     * 当前值显示文字
     */
    val tvShowValue get() = mBinding.tvShowValue

    /**
     * 滑动按钮
     */
    val ivSliderBtn get() = mBinding.ivSliderBtn

    /**
     * 滑动条
     */
    val iclSliderBarAccent get() = mBinding.iclSliderBarAccent

    /**
     * 滑动条背景
     */
    val iclSliderBarBackground get() = mBinding.iclSliderBarBackground

    /**
     * 当前值显示框
     */
    val iclSliderIndicator get() = mBinding.iclSliderIndicator

    /**
     * 格式化显示数字
     */
    private fun getValueString(value: Float): String {
        var limit = if (decimalLimit > 0) "." else ""
        for (i in 1..decimalLimit) {
            limit += "#"
        }
        return DecimalFormat("0$limit").apply {
            roundingMode = RoundingMode.FLOOR
        }.format(value)
    }

    /**
     * 重置视图
     */
    fun resetView(resetViewListener: (binding: LayoutSliderSelectorBinding) -> Unit) {
        this.resetViewListener = resetViewListener
        this.resetViewListener?.invoke(mBinding)
    }

    /**
     * 设置滑动监听
     */
    fun setOnSlidingListener(onSlidingListener: (binding: LayoutSliderSelectorBinding, value: Float, position: Float, event: MotionEvent) -> Unit) {
        this.onSlidingListener = onSlidingListener
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun initView() {
        //计算基础参数（post会在onLayout后执行）
        this.post {
            val rectLeft = Rect()
            val rectRight = Rect()
            mBinding.apply {
                iclSliderBarAccent.getHitRect(rectLeft)
                iclSliderBarBackground.getHitRect(rectRight)
            }
            sliderBarLeft = rectLeft.left
            sliderBarRight = rectRight.right
            sliderLength = sliderBarRight - sliderBarLeft
        }

        mBinding.apply {
            ivSliderBtn.setOnTouchListener { _, event ->
                if (event.action == MotionEvent.ACTION_MOVE) {
                    //计算当前位置（百分比）
                    val pos = (event.rawX - sliderBarLeft) / sliderLength
                    when {
                        pos > 1f -> position = 1f
                        pos < 0f -> position = 0f
                        //如果grainyValue != 0 时，滑动时会具有颗粒感
                        abs(pos - position) >= grainyValue -> position = pos
                    }
                    if (maxValue >= minValue) value = (maxValue - minValue) * position + minValue
                }
                onSlidingListener?.invoke(this, formattedValue, position, event)
                return@setOnTouchListener true
            }
        }
    }

}